<?php

namespace app\api\logic;

use app\api\cache\RedisCache;
use app\api\consDir\ErrorConst;
use app\api\services\LotteryService;
use app\api\services\MemberInfoService;
use app\api\services\MemberService;
use app\common\libs\Singleton;
use app\common\models\Marketing\Lottery;
use app\common\models\Marketing\LotteryAward;
use app\common\models\Marketing\LotteryData;
use app\common\models\Marketing\LotteryLog;
use app\common\models\Marketing\LotteryMember;
use app\common\models\Marketing\LotteryRead;
use app\common\models\Member\MemberNum;
use app\common\utils\CommonUtil;
use app\common\utils\RedLock;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

class LotteryLogic extends BaseLogic
{
    use Singleton;

    /**
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws DataNotFoundException
     */
    public function lotteryData(): array
    {
        return LotteryService::getInstance()->lotteryData();
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function awardList(): array
    {
        $list = LotteryService::getInstance()->awardList();
        $memberNum = MemberInfoService::getInstance()->memberNum($this->userinfo->id);
        $count = $memberNum['lotteryCount'] ?? 0;
        return ['rows' => $list, 'count' => $count];
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function lottery(): array
    {
        if (!RedLock::getInstance()->lock('lottery:' . $this->userinfo->id, 1)) {
            CommonUtil::throwException(ErrorConst::FREQUENT_ERROR, ErrorConst::FREQUENT_ERROR_MSG);
        }
        $where = [
            ['status', '=', 1],
            ['is_switch', '=', 1],
            ['deleted', '=', 0],
        ];
        $lottery = Lottery::getInstance()->where($where)->find();
        if (empty($lottery)) {
            CommonUtil::throwException(ErrorConst::PARAM_ERROR, '抽奖活动未开始');
        }
        $now = date('Y-m-d H:i:s');
        if ($now < $lottery['startTime'] || $now > $lottery['endTime']) {
            CommonUtil::throwException(ErrorConst::PARAM_ERROR, '抽奖活动未开始!');
        }
        $memberNum = MemberInfoService::getInstance()->memberNum($this->userinfo->id);
        if ($memberNum['lotteryCount'] < 1) {
            CommonUtil::throwException(ErrorConst::PARAM_ERROR, $lottery['tips']);
        }
        if($lottery['userCount'] < 1){
            CommonUtil::throwException(ErrorConst::PARAM_ERROR, '未设置次数上限');
        }
        if($lottery['joinType'] == 0){
            if($lottery['consumeGxz'] > 0){
                $finance = MemberService::getInstance()->finance($this->userinfo->id);
                if($finance['gxz'] < $lottery['consumeGxz']){
                    CommonUtil::throwException(ErrorConst::PARAM_ERROR, '贡献值不足');
                }
            }
            if($lottery['joinCountType'] == 0){
                //每天
                $where = [
                    ['create_at','>=',date('Y-m-d')],
                ];
                $perDay = LotteryData::getInstance()->where($where)->count();
                if($perDay > $lottery['perDay']){
                    CommonUtil::throwException(ErrorConst::PARAM_ERROR, '每天参与上限'.$lottery['perDay'].'次');
                }
            }else{
                //每人
                $where = [
                    ['user_id','=',$this->userinfo->id],
                    ['create_at','>=',date('Y-m-d')],
                ];
                $perDay = LotteryData::getInstance()->where($where)->count();
                if($perDay > $lottery['perNum']){
                    CommonUtil::throwException(ErrorConst::PARAM_ERROR, '每人参与上限'.$lottery['perNum'].'次');
                }
            }
        }else{
            $where = [
                ['user_id','=',$this->userinfo->id],
                ['create_at','>=',date('Y-m-d')],
            ];
            $count = LotteryData::getInstance()->where($where)->count();
            if($count >= $lottery['userCount']){
                CommonUtil::throwException(ErrorConst::PARAM_ERROR, '每人每天抽奖次数上限'.$lottery['userCount'].'次');
            }
        }
        $rand = mt_rand(1, 100);
        if ($rand > $lottery['winRate']) {
            LotteryService::getInstance()->noWin($this->userinfo->id,1,$lottery);
            CommonUtil::throwException(ErrorConst::PARAM_ERROR, $lottery['tips']);
        }
        $lotteryAward = null;
        $lockKey = 'lottery:lock';
        $lockValue = uniqid();
        $lock = RedisCache::set($lockKey, $lockValue, ['NX', 'EX' => 2]);
        if($lock){
            $lotteryAward = LotteryService::getInstance()->getLotteryAward($this->userinfo->id,$lottery);
            if (empty($lotteryAward)) {
                LotteryService::getInstance()->noWin($this->userinfo->id,1,$lottery);
                if(RedisCache::get($lockKey) == $lockValue){
                    RedisCache::del($lockKey);
                }
                CommonUtil::throwException(ErrorConst::PARAM_ERROR, $lottery['tips']);
            }
            LotteryData::getInstance()->startTrans();
            try {
                $ret = LotteryService::getInstance()->win($this->userinfo->id,1,$lottery,$lotteryAward);
                if($ret === false){
                    LotteryData::getInstance()->rollback();
                    CommonUtil::throwException(ErrorConst::PARAM_ERROR, '抽奖失败');
                }
            } catch (\Exception $e) {
                LotteryData::getInstance()->rollback();
                CommonUtil::throwException(ErrorConst::PARAM_ERROR, $e->getMessage());
            } finally {
                if(RedisCache::get($lockKey) == $lockValue){
                    RedisCache::del($lockKey);
                }
            }
            LotteryData::getInstance()->commit();
        }else{
            CommonUtil::throwException(ErrorConst::PARAM_ERROR, '请求频繁');
        }
        return ['award_id' => $lotteryAward['id'] ?? 0];
    }

    public function rule(): array
    {
        $where = [
            ['deleted', '=', 0],
        ];
        $content = Lottery::getInstance()->where($where)->order('id')->value('content');
        return ['content' => $content];
    }

    /**
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws DataNotFoundException
     */
    public function userLotteryList($page, $pageSize): array
    {
        return LotteryService::getInstance()->userLotteryList($this->userinfo->id, $page, $pageSize);
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function read(): array
    {
        $where = [
            ['is_read', '=', 0],
            ['user_id','=',$this->userinfo->id]
        ];
        $read = LotteryLog::getInstance()->where($where)->find();
        if(empty($read)){
            return [];
        }
        $read->isRead = 1;
        $read->update_at = date('Y-m-d H:i:s');
        $read->save();
        return $read->toArray();
    }

    /**
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws DataNotFoundException
     */
    public function lotteryInfo(): array
    {
        return LotteryService::getInstance()->lotteryInfo();
    }
}